﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace LuaBoard
{

    public partial class FileCopyForm : Form
    {
        public List<FileCopyData> fileCopyData = new List<FileCopyData>();

        private BackgroundWorker mCopier;
        private delegate void ProgressChanged(UIProgress info);
        private delegate void CopyError(UIError err);
        private ProgressChanged OnChange;
        private CopyError OnError;
        private bool DoCancel = false;
        private bool stop = true;

        public FileCopyForm(string title)
        {
            InitializeComponent();
            this.Text = title;
            mCopier = new BackgroundWorker();
            mCopier.DoWork += Copier_DoWork;
            mCopier.RunWorkerCompleted += Copier_RunWorkerCompleted;
            mCopier.WorkerSupportsCancellation = true;
            OnChange += Copier_ProgressChanged;
            OnError += Copier_Error;
            ChangeUI(true);
            
        }
        public void run()
        {
            stop = false;
            mCopier.RunWorkerAsync();
            while (!stop)
            {
                System.Threading.Thread.Sleep(100);
            }
            this.Close();
        }
        private void Copier_DoWork(object sender, DoWorkEventArgs e)
        {
            
            List<FileCopyData> files = new List<FileCopyData>();

            long maxbytes = 0;
            foreach (FileCopyData fcd in fileCopyData)
            {
                if (!fcd.IsDir)
                {
                    maxbytes += fcd.Maxbytes;
                    files.Add(fcd);
                }
                else
                {
                    maxbytes += fcd.Maxbytes;
                    int str_index = fcd.SourcePath.Length;
                    foreach (FileInfo file in fcd.folder)
                    {
                        if ((file.Attributes & FileAttributes.Directory) != 0) continue;

                        string dn = file.FullName.Substring(str_index);
                        string dist = Path.Combine(fcd.DistPath, dn);
                        
                        FileCopyData FCD = new FileCopyData(file.FullName, dist, fcd.Overwite, fcd.Move);
                        files.Add(FCD);
                    }

                }
            }
            // Copy files
            long bytes = 0;
            foreach (FileCopyData file in files)
            {
                try
                {
                    this.BeginInvoke(OnChange, new object[] { new UIProgress(file.SourceFileInfo.Name, bytes, maxbytes,file.Move) });
                    if (File.Exists(file.DistPath))
                    {
                        if (file.Overwite)
                        {
                            File.Delete(file.DistPath);
                            if (File.Exists(file.DistPath))
                            {
                                UIError err = new UIError("Can not overwrite files.", file.DistPath);
                                this.Invoke(OnError, new object[] { err });
                                if (err.result == DialogResult.Cancel) break;
                            }
                        }
                        else
                        {
                            UIError err = new UIError("File already exists.", file.DistPath);
                            this.Invoke(OnError, new object[] { err });
                            if (err.result == DialogResult.Cancel) break;
                        }
                    }
                    string dist_dir = Path.GetDirectoryName(file.DistPath);
                    if (!Directory.Exists(dist_dir)) Directory.CreateDirectory(dist_dir);
                    if (file.Move)
                        
                        File.Move(file.SourcePath, file.DistPath);
                    else
                        File.Copy(file.SourcePath, file.DistPath, file.Overwite);
                }
                catch (Exception ex)
                {
                    UIError err = new UIError(ex.Message, file.SourcePath);
                    this.Invoke(OnError, new object[] { err });
                    if (err.result == DialogResult.Cancel) break;
                }
                bytes += file.SourceFileInfo.Length;
                if (DoCancel) break;
            }
            stop = true;
        }
        private void Copier_ProgressChanged(UIProgress info)
        {
            // Update progress
            progressBar1.Value = (int)(100.0 * info.bytes / info.maxbytes);
            label1.Text = "Copying " + info.name;
        }
        private void Copier_Error(UIError err)
        {
            // Error handler
            string msg = string.Format("Error copying file {0}\n{1}\nClick OK to continue copying files", err.path, err.msg);
            err.result = MessageBox.Show(msg, "Copy error", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
        }
        private void Copier_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Operation completed, update UI
            ChangeUI(false);
        }
        private void ChangeUI(bool docopy)
        {
            label1.Visible = docopy;
            progressBar1.Visible = docopy;
            label1.Text = "Starting copy...";
            progressBar1.Value = 0;
        }
        // Class to report progress
        private class UIProgress
        {
            public UIProgress(string name_, long bytes_, long maxbytes_,bool move_)
            {
                name = name_; bytes = bytes_; maxbytes = maxbytes_; move = move_;
            }
            public string name;
            public long bytes;
            public long maxbytes;
            public bool move;
        }
        // Class to report exception {
        private class UIError
        {
            public UIError(string ex, string path_)
            {
                msg = ex; path = path_; result = DialogResult.Cancel;
            }
            public string msg;
            public string path;
            public DialogResult result;
        }


        private void FileCopyForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            DoCancel = true;
            //mCopier.CancelAsync();
            while (!stop)
            {
                System.Threading.Thread.Sleep(100);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            DoCancel = true;
            ChangeUI(false);
        }

        private void FileCopyForm_Load(object sender, EventArgs e)
        {
            run();
        }


    }

    public class FileCopyData
    {
        private string _sourcePath;
        private string _distPath;
        private bool _overwrite;
        private bool _move;
        private bool _IsDir;
        private long _maxbytes;
        public string ext = "*.*";
        public FileInfo[] folder;

        public FileInfo SourceFileInfo;


        public FileCopyData(string sourcePath, string distPath, bool overwite)
        {
            if (!File.Exists(sourcePath) && Directory.Exists(sourcePath)) _IsDir = true;
            _sourcePath = sourcePath;
            _distPath = distPath;
            _overwrite = overwite;
            _move = false;
            
            SourceFileInfo = new FileInfo(sourcePath);
            GetMaxBytes();
        }

        public FileCopyData(string sourcePath, string distPath, bool overwite,bool move)
        {
            if (!File.Exists(sourcePath) && Directory.Exists(sourcePath)) _IsDir = true;
            _sourcePath = sourcePath;
            _distPath = distPath;
            _overwrite = overwite;
            _move = move;
            SourceFileInfo = new FileInfo(sourcePath);
            GetMaxBytes();
        }
        public FileCopyData(string sourcePath, string distPath, bool overwite, bool move,string Ext)
        {
            if (!File.Exists(sourcePath) && Directory.Exists(sourcePath)) _IsDir = true;
            _sourcePath = sourcePath;
            _distPath = distPath;
            _overwrite = overwite;
            _move = move;
            SourceFileInfo = new FileInfo(sourcePath);
            ext = Ext;
            GetMaxBytes();
        }

        private void GetMaxBytes()
        {
            _maxbytes = 0;
            if (_IsDir)
            {
                DirectoryInfo dir = new DirectoryInfo(_sourcePath);
                folder = dir.GetFiles(ext, SearchOption.AllDirectories);

                foreach (FileInfo file in folder)
                {
                    if ((file.Attributes & FileAttributes.Directory) != 0) continue;
                    _maxbytes += file.Length;
                }
            }
            else
            {
                _maxbytes = SourceFileInfo.Length;
            }
        }
        public string SourcePath
        {
            get { return _sourcePath; }
        }
        public string DistPath
        {
            get { return _distPath; }
        }
        public bool Overwite
        {
            get { return _overwrite; }
        }
        public bool Move
        {
            get { return _move; }
        }
        public bool IsDir
        {
            get { return _IsDir; }
        }
        public long Maxbytes
        {
            get { return _maxbytes; }
        }
    }

}
